package com.xzz.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.xzz.doc.CourseDoc;
import com.xzz.domain.*;
import com.xzz.dto.CourseDto;
import com.xzz.dto.PreOrderDto;
import com.xzz.enums.GlobalErrorCode;
import com.xzz.feign.MediaFeignClient;
import com.xzz.feign.SearchFeignClient;
import com.xzz.mapper.CourseMapper;
import com.xzz.mapper.CourseTypeMapper;
import com.xzz.result.JSONResult;
import com.xzz.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.xzz.util.AssertUtil;
import com.xzz.vo.CourseInfoVo;
import com.xzz.vo.OrderInfoVo;
import com.xzz.vo.OrderItemInfoVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xzz
 * @since 2022-09-02
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ICourseDetailService courseDetailService;

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseMarketService courseMarketService;

    @Autowired
    private ICourseResourceService courseResourceService;

    @Autowired
    private ICourseSummaryService courseSummaryService;

    @Autowired
    private CourseTypeMapper courseTypeMapper;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private SearchFeignClient searchFeignClient;

    @Autowired
    private ICourseTeacherService courseTeacherService;

    @Autowired
    private ICourseChapterService courseChapterService;

    @Autowired
    private MediaFeignClient mediaFeignClient;

    @Autowired
    private ICourseUserLearnService courseUserLearnService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Override
    @Transactional
    public void save(CourseDto courseDto) {
        Course course = courseDto.getCourse();
        CourseDetail courseDetail = courseDto.getCourseDetail();
        CourseMarket courseMarket = courseDto.getCourseMarket();
        CourseResource courseResource = courseDto.getCourseResource();
        List<Long> teacherIds = courseDto.getTeacherIds();
        // 1.参数校验，使用JSR303
        // 2.课程是否重复，如果重复不允许添加
        Course courseTmp = selectByName(course.getName());
        AssertUtil.isNull(courseTmp, GlobalErrorCode.COURSE_EXISTED_ERROR);

        // 3.保存课程
        saveCourse(course, teacherIds);
        // 3.1.新增之后返回主键ID
        Long courseId = course.getId();

        // 4.保存详情信息
        courseDetail.setId(courseId);
        courseDetailService.insert(courseDetail);

        // 5.保存营销信息
        courseMarket.setId(courseId);
        courseMarketService.insert(courseMarket);

        // 6.保存资源信息
        courseResource.setCourseId(courseId);
        courseResourceService.insert(courseResource);

        // 7.初始化课程统计信息
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(courseId);
        courseSummaryService.insert(courseSummary);

        // 8.保存讲师中间表信息
        courseMapper.insertCourseTeacher(courseId, teacherIds);

        // 9.给对应课程类型数量加一
        courseTypeMapper.updateTotalCountById(course.getCourseTypeId());
    }

    //保存课程
    private void saveCourse(Course course, List<Long> teacherIds) {
        // 1.初始化参数
        // 1.1.设置初始状态为下架
        course.setStatus(Course.STATUS_OFFLINE);
        // 1.2.添加员工暂时写死，后面做了登录回来修改
        course.setLoginId(6L);
        course.setLoginUserName("itsource.cn");
        course.setChapterCount(0);
        // 1.3.讲师需要查询之后进行讲师名称设置
        List<Teacher> teachers = teacherService.selectBatchIds(teacherIds);
        // 集合变成stream流，map映射取值，collect最终操作，collection：数据转换，joining：拼接操作
        String teacherStr = teachers.stream().map(Teacher::getName).collect(Collectors.joining(","));
        course.setTeacherNames(teacherStr);
        // 2.保存课程信息
        insert(course);
    }

    //根据课程名称查询课程，防止课程名称重复
    private Course selectByName(String name) {
        Wrapper<Course> tWrapper = new EntityWrapper<Course>();
        tWrapper.eq("name", name);
        return selectOne(tWrapper);
    }

    @Override
    @Transactional
    public void onLineCourse(Long courseId) {
        // 1.参数校验
        AssertUtil.isNotNull(courseId,"课程不能重复");
        // 2.业务校验
        Course course = selectById(courseId);
        //  2.1课程必须存在
        AssertUtil.isNotNull(course,"课程不存在");
        //  2.2课程状态必须是下架状态
        AssertUtil.isTrue(course.getStatus() == Course.STATUS_OFFLINE,"课程已经上架");
        // 3.修改课程状态（上架）+ 填写上架时间
        course.setStatus(Course.STATUS_ONLINE);
        course.setOnlineTime(new Date());

        updateById(course);

        // 4.将课程通过Feign 调用service-search保存到Es中
        CourseDoc courseDoc = new CourseDoc();
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        BeanUtils.copyProperties(course,courseDoc);
        BeanUtils.copyProperties(courseMarket,courseDoc);
        BeanUtils.copyProperties(courseSummary,courseDoc);
        //额外参数
        courseDoc.setChargeName(courseMarket.getCharge().intValue()==1 ? "收费":"免费");
        //上线课程的时候，就会添加进入到ES里面去
        JSONResult jsonResult = searchFeignClient.saveCourseDoc(courseDoc);
        AssertUtil.isTrue(jsonResult.isSuccess(),"发布课程失败");
    }

    @Override
    public CourseInfoVo courseInfo(Long courseId) {

        AssertUtil.isNotNull(courseId,"课程不能为空");
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"不存在");
        AssertUtil.isTrue(course.getStatus()==Course.STATUS_ONLINE,"已经下架");

        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        CourseMarket courseMarket = courseMarketService.selectById(courseId);

        //通过中间表，课程-老师，获得老师id的集合
        EntityWrapper<CourseTeacher> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id",courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(wrapper);

        //上面中间表获得老师id的集合，通过老师id的集合，查询老师
        List<Long> ids = courseTeachers.stream().map(CourseTeacher::getTeacherId).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(ids);

        //查询课程章节
        List<CourseChapter> courseChapters = courseChapterService.listByCourseId(courseId);

        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream()
                .collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));

        //使用feign接口调用media视频
        JSONResult jsonResult = mediaFeignClient.queryMediaByCourseId(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(), "查询媒体失败");

        if(jsonResult.getData()!=null){
            List<MediaFile> mediaFiles = JSON.parseArray(jsonResult.getData().toString(), MediaFile.class);
            for (MediaFile mediaFile : mediaFiles) {
                mediaFile.setFileUrl("");
                CourseChapter courseChapter = courseChapterMap.get(mediaFile.getChapterId());
                if (courseChapter != null){
                    courseChapter.getMediaFiles().add(mediaFile);
                }
            }
        }

        return new CourseInfoVo(course,courseMarket,courseChapters,teachers,courseDetail,courseSummary);
    }

    @Override
    public String getForUser(Long mediaId) {
        AssertUtil.isNotNull(mediaId,"id不能为空");

        //通过feign查看媒体信息
        JSONResult jsonResult = mediaFeignClient.get(mediaId);
        AssertUtil.isNotNull(jsonResult.getData(),"媒体信息不存在");
        MediaFile mediaFile = JSON.parseObject(jsonResult.getData().toString(), MediaFile.class);

        //判断是否免费
        if (mediaFile.getFree()){
            return mediaFile.getFileUrl();
        }

        //通过联合索引，查看唯一登入人的对唯一课程的数据
        Long loginId=3L;
        EntityWrapper<CourseUserLearn> wrapper = new EntityWrapper<>();
        wrapper.eq("login_id",loginId);
        wrapper.eq("course_id",mediaFile.getCourseId());
        CourseUserLearn courseUserLearn = courseUserLearnService.selectOne(wrapper);

        //判断是否购买课程
        AssertUtil.isNotNull(courseUserLearn,"未购买课程");

        //如果已经购买，判断时间是否过期
        boolean before = new Date().before(courseUserLearn.getEndTime());
        AssertUtil.isTrue(before,"课程时间已经过期，请续费");

        return mediaFile.getFileUrl();

    }

    @Override
    public OrderInfoVo orderInfo(String courseIds) {
        AssertUtil.isNotEmpty(courseIds,"空");
        String[] split = courseIds.split(",");
        List<Course> courses = selectBatchIds(Arrays.asList(split));
        AssertUtil.isTrue(split.length==courses.size(),"不匹配");

        OrderInfoVo orderInfoVo = new OrderInfoVo();

        //查询出来每个课程，对应的课程销售数据
        for (Course cours : courses) {
            AssertUtil.isTrue(cours.getStatus().intValue()==Course.STATUS_ONLINE.intValue(),"下架");
            CourseMarket courseMarket = courseMarketService.selectById(cours.getId());
            OrderItemInfoVo orderItemInfoVo = new OrderItemInfoVo(cours, courseMarket);
            //类里面有集合，一般初始化，后面不用set，直接get出来，add添加进去
            orderInfoVo.getCourseInfos().add(orderItemInfoVo);
            //金额的add方法，可以进行累加用add，算出总金额
            orderInfoVo.setTotalAmount(orderInfoVo.getTotalAmount().add(courseMarket.getPrice()));
        }
        return orderInfoVo;
    }

    /**
     * 查询秒杀订单，构成结算页数据
     * @param orderNo
     * @return
     */
    @Override
    public OrderInfoVo oneByOrder(String orderNo) {
        //查询预创订单
        Object tmp = redisTemplate.opsForValue().get(orderNo);
        AssertUtil.isNotNull(tmp,"下单错误，信息不存在！！！");
        PreOrderDto orderDto = (PreOrderDto)tmp;

        // 3.批量查询Course
        Course course = selectById(orderDto.getCourseId());
        // 大VO OrderInfoVo
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 5.查找课程对应的销售信息
        CourseMarket courseMarket = courseMarketService.selectById(course.getId());
        // 此处价格是秒杀价
        courseMarket.setPrice(orderDto.getTotalAmount());
        OrderItemInfoVo orderItemInfo = new OrderItemInfoVo(course, courseMarket);

        //构成结算页数据
        orderInfoVo.getCourseInfos().add(orderItemInfo);
        orderInfoVo.setTotalAmount(orderDto.getTotalAmount());

        return orderInfoVo;
    }
}
